#    Copyright 2012 New Mexico EPSCoR
#
#    This file is part of Teacher's P.E.T.
#
#    Teacher's P.E.T. is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    Teacher's P.E.T. is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with Teacher's P.E.T..  If not, see <http://www.gnu.org/licenses/>.
from django.shortcuts import render_to_response, get_object_or_404
from django.core.exceptions import ObjectDoesNotExist
from django.template import RequestContext
from django.http import Http404, HttpResponseRedirect, HttpResponse
from django.contrib import messages
from django.utils.encoding import smart_str
from django.db.models import Q

from filetransfers.api import serve_file
from options import Options
from apps.management import Management
from apps.course.models import Course
from apps.course.functions import course_reverse, remove_course
from apps.participants.models import CourseParticipant
from tags.templatetags.natural_sort import natural_sort
from models import *

import logging
import urllib

logger = logging.getLogger('pet.apps.forum.manage')

@Options.option_enabled
def manage(request, TheCourseParticipant, TheCourse):
	logger.fxn_entry('Entering forum management')
	TheForum = TheCourse.forum
	AttachForm = None
	TaggedEntries = []
	TaggedThreads = []
	TaggedMessages = []
	BlockList = []
	Bans = []
	if TheForum:
		TaggedMessages = ForumPrivateMessage.objects.filter(forum=TheForum,flagged_date__isnull=False)
		for msg in TaggedMessages:
			msg.sender.course_participant = CourseParticipant.find(TheCourse.course_id,user=msg.sender)
		TaggedThreads = ForumThread.find(forum=TheForum,is_deleted=True,keep_queryset=True)
		for thread in TheForum.threads.all():
			TaggedEntries += list(thread.entries.filter(Q(flagged_for_moderator=True)|Q(flagged_as_deleted=True)))
		Bans = ForumBan.objects.filter(forum=TheForum)
		BlockList = []
		CPs = CourseParticipant.objects.none()
		for course in TheForum.courses.all():
			CPs |= CourseParticipant.find(course,keep_queryset=True)
		BlockList = natural_sort([(cp,ForumPrivateMessageBlock.objects.filter(blocked=cp.user)) for cp in CPs],key = lambda item: "%s %s %s" % (1000-len(item[1]),item[0].user.last_name,item[0].user.first_name))
		if len(BlockList[0][1]) <= 0: BlockList = []
	else:
		AttachForm = AttachForumForm()
	
	TaggedEntries = sorted(TaggedEntries,key=lambda item: "%s" % ("1" if item.is_marked_for_moderator() and not item.is_deleted() else "2"))
	
	logger.fxn_exit("Returning forum management")
	return render_to_response('forum/management/manage.html',{'Forum':TheForum, 'Bans':Bans,
			'TaggedEntries':TaggedEntries, 'TaggedThreads':TaggedThreads, 'TaggedMessages':TaggedMessages,
			'BlockList':BlockList,'AttachForm':AttachForm},context_instance=RequestContext(request))
Management.register_interface('Forum','ASSISTANT;INSTRUCTOR','manage',manage)

def attach_forum(request, TheCourseParticipant, TheCourse):
	logger.fxn_entry('Attaching preexisting forum for course %s',TheCourse)
	
	if TheCourse.forum:
		logger.forced_redirect("Unable to attach forum to course %s, course already has forum",TheCourse)
		messages.info(request,"A forum already exists for this course, it must be deleted first")
		return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
	
	if request.method == "POST":
		form = AttachForumForm(request.POST)
		if form.is_valid():
			if form.cleaned_data['forum']:
				TheForum = form.cleaned_data['forum']
				TheCourse.forum = TheForum
				TheCourse.save()
				logger.info("Successfully attached forum %s to course %s",TheForum,TheCourse)
				messages.info(request,"Forum %s has been successfully attached to this course"%TheForum)
				return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
			else: logger.error("'forum' not found in cleaned_data. What went wrong?")
		else:
			logger.error("Invalid ForumAttachForm form %s",form)
			messages.error(request,"Error attaching forum to course. Please try again.")
			return manage(request,TheCourseParticipant,TheCourse)
	
	logger.info("attach_forum incorrectly called. Returning to forum management")
	return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
Management.register_interface('Forum','ASSISTANT;INSTRUCTOR','attach',attach_forum)
   
def create_new_forum(request, TheCourseParticipant, TheCourse):
	logger.fxn_entry('Creating new forum for course %s' % TheCourse)
	
	if TheCourse.forum:
		logger.forced_redirect("Unable to create a new forum in course %s, forum already exists",TheCourse)
		messages.info(request,"A forum already exists for this course, it must be deleted first")
		return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
	
	if request.method == "POST":
		if 'title' in request.POST:
			if len(str(request.POST['title'])) <= 0:
				messages.error(request,"A title is required when creating a forum")
				return manage(request,TheCourseParticipant,TheCourse)
			TheForum = Forum(title = str(request.POST['title']))
			TheForum.save()
			TheCourse.forum = TheForum
			TheCourse.save()
			logger.info("Successfully create forum %s and attached to course %s",TheForum,TheCourse)
			messages.info(request, "Forum '%s' successfully created" % TheForum)
			return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
	
	logger.fxn_exit("create_new_forum incorrectly called. Returning to forum management")
	return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
Management.register_interface('Forum','ASSISTANT;INSTRUCTOR','create',create_new_forum)

@Options.option_enabled
def delete(request, TheCourseParticipant, TheCourse):
	logger.fxn_entry('Deleting forum for course %s' % TheCourse)
	TheForum = TheCourse.forum
	if not TheForum:
		logger.forced_redirect("Unable to delete forum for course %s, no forum exists for this course")
		messages.info(request,"No forum exists for this course, nothing to delete")
		return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
	
	if request.method == 'POST':
		TheCourse.forum = None
		TheCourse.save()
		if TheForum.courses.count() == 0:
			TheForum.delete()
			messages.info(request,"Forum %s deleted" % TheForum)
			logger.fxn_exit("Forum %s deleted" % TheForum)
		else:
			messages.info(request,"Forum %s removed from this course" % TheForum)
			logger.fxn_exit("Forum %s removed from course %s" % (TheForum,TheCourse))
		return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
	
	logger.fxn_exit("Showing forum delete confirmation")
	return render_to_response('forum/management/delete.html',{'TheForum':TheForum,'TheCourse':TheCourse},context_instance=RequestContext(request))
Management.register_interface('Forum','ASSISTANT;INSTRUCTOR','delete',delete)

def alter_message(request, TheCourseParticipant, TheCourse, message_id, option):
	logger.fxn_entry('Altering message %s with option "%s"',message_id,option)
	TheMessage = ForumPrivateMessage.objects.filter(pk=message_id)
	if not TheMessage:
		logger.http404("Message with id %s not found",message_id)
		raise Http404
	else: TheMessage = TheMessage[0]
	
	if option == "unflag":
		if TheMessage.is_marked_for_moderator():
			TheMessage.mark_reviewed_by_moderator(); TheMessage.save();
			messages.info(request,"Message unflagged")
			logger.fxn_exit("Message %s (%s) unflagged" % (TheMessage, TheMessage.id))
		else:
			messages.info(request,"Message not flagged")
			logger.fxn_exit("Message %s (%s) not flagged. Doing nothing." % (TheMessage, TheMessage.id))
	elif option == "hide":
		if not TheMessage.is_hidden():
			TheMessage.mark_hidden(); TheMessage.save();
			messages.info(request,"Message hidden")
			logger.fxn_exit("Message %s marked as hidden" % (TheMessage.id))
		else:
			messages.info(request,"Message already hidden")
			logger.fxn_exit("Message %s already marked as hidden. Doing nothing." % (TheMessage.id))
	elif option == "unhide":
		if TheMessage.is_hidden():
			TheMessage.mark_unhidden(); TheMessage.save();
			messages.info(request,"Message unhidden")
			logger.fxn_exit("Message %s unhidden" % (TheMessage.id))
		else:
			messages.info(request,"Message hadn't been hidden")
			logger.fxn_exit("Message %s hadn't been hidden. Doing nothing." % (TheMessage.id))
	else:
		messages.info(request,"Invalid option selected. Please try again.")
		logger.fxn_exit("Option %s makes no sense. Doing nothing." % option)
	
	return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
Management.register_interface('Forum','ASSISTANT;INSTRUCTOR','alter_message',alter_message)

def alter_entry(request, TheCourseParticipant, TheCourse, entry_id, option):
	logger.fxn_entry('Altering entry %s with option "%s"',entry_id,option)
	TheEntry = ForumEntry.find_or_404(id=entry_id)
	
	if option == "unflag":
		if TheEntry.is_marked_for_moderator():
			TheEntry.mark_reviewed_by_moderator(); TheEntry.save();
			messages.info(request,"Post %s of thread %s unflagged" % (TheEntry.entry_number, TheEntry.thread.title))
			logger.fxn_exit("Post %s of thread '%s' unflagged" % (TheEntry.entry_number, TheEntry.thread.title))
		else:
			messages.info(request,"Post not flagged")
			logger.fxn_exit("Post %s of thread '%s' not flagged. Doing nothing." % (TheEntry.entry_number, TheEntry.thread.title))
	elif option == "hide":
		if not TheEntry.is_deleted():
			TheEntry.mark_deleted(); TheEntry.save();
			messages.info(request,"Post %s of thread %s hidden" % (TheEntry.entry_number, TheEntry.thread.title))
			logger.fxn_exit("Post %s of thread '%s' marked as hidden" % (TheEntry.entry_number, TheEntry.thread.title))
		else:
			messages.info(request,"Post already hidden")
			logger.fxn_exit("Post %s of thread '%s' already hidden. Doing nothing." % (TheEntry.entry_number, TheEntry.thread.title))
	elif option == "unhide":
		if TheEntry.is_deleted():
			TheEntry.mark_undeleted(); TheEntry.save();
			messages.info(request,"Post %s of thread '%s' unhidden" % (TheEntry.entry_number, TheEntry.thread.title))
			logger.fxn_exit("Post %s of thread '%s' unhidden" % (TheEntry.entry_number, TheEntry.thread.title))
		else:
			messages.info(request,"Post hadn't been hidden")
			logger.fxn_exit("Post %s of thread '%s' hadn't been hidden. Doing nothing." % (TheEntry.entry_number, TheEntry.thread.title))
	else:
		messages.info(request,"Invalid option selected. Please try again.")
		logger.fxn_exit("Option %s makes no sense. Doing nothing." % option)
	
	return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
Management.register_interface('Forum','ASSISTANT;INSTRUCTOR','alter_entry',alter_entry)

def alter_thread(request, TheCourseParticipant, TheCourse, thread_id, option, src):
	logger.fxn_entry('Altering thread %s with option "%s" from "%s"',thread_id,option,src)
	TheForum = TheCourse.forum
	if not TheForum:
		messages.error(request,"No forum attached to this course")
		logger.forced_redirect("No forum attached to course %s",TheCourse)
		return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
	TheThread = ForumThread.find_or_404(forum=TheForum,id=thread_id)
	
	if option == "sticky":
		if not TheThread.is_sticky():
			TheThread.mark_sticky(); TheThread.save();
			messages.info(request,"Thread '%s' marked sticky" % (TheThread.title))
			logger.fxn_exit("Thread '%s' marked sticky" % (TheThread.title))
		else:
			messages.info(request,"Thread already marked sticky")
			logger.fxn_exit("Thread '%s' already marked stciky. Doing nothing." % (TheThread.title))
	elif option == "unsticky":
		if TheThread.is_sticky():
			TheThread.mark_unsticky(); TheThread.save();
			messages.info(request,"Thread '%s' unstickied" % (TheThread.title))
			logger.fxn_exit("Thread '%s' unstickied" % (TheThread.title))
		else:
			messages.info(request,"Thread hadn't been sticky")
			logger.fxn_exit("Thread '%s' hadn't been sticky. Doing nothing." % (TheThread.title))
	elif option == "lock":
		if not TheThread.is_locked():
			TheThread.mark_locked(); TheThread.save();
			messages.info(request,"Thread '%s' locked" % (TheThread.title))
			logger.fxn_exit("Thread '%s' locked" % (TheThread.title))
		else:
			messages.info(request,"Thread already locked")
			logger.fxn_exit("Thread '%s' already locked. Doing nothing." % (TheThread.title))
	elif option == "unlock":
		if TheThread.is_locked():
			TheThread.mark_unlocked(); TheThread.save();
			messages.info(request,"Thread '%s' unlocked" % (TheThread.title))
			logger.fxn_exit("Thread '%s' unlocked" % (TheThread.title))
		else:
			messages.info(request,"Thread hadn't been locked")
			logger.fxn_exit("Thread '%s' hadn't been locked. Doing nothing." % (TheThread.title))
	elif option == "hide":
		if not TheThread.is_deleted():
			TheThread.mark_deleted(); TheThread.save();
			messages.info(request,"Thread '%s' hidden" % (TheThread.title))
			logger.fxn_exit("Thread '%s' hidden" % (TheThread.title))
		else:
			messages.info(request,"Thread already hidden")
			logger.fxn_exit("Thread '%s' already hidden. Doing nothing." % (TheThread.title))
	elif option == "unhide":
		if TheThread.is_deleted():
			TheThread.mark_undeleted(); TheThread.save();
			messages.info(request,"Thread '%s' unhidden" % (TheThread.title))
			logger.fxn_exit("Thread '%s' unhidden" % (TheThread.title))
		else:
			messages.info(request,"Thread hadn't been hidden")
			logger.fxn_exit("Thread '%s' hadn't been hidden. Doing nothing." % (TheThread.title))
	else:
		messages.info(request,"Invalid option selected. Please try again.")
		logger.fxn_exit("Option %s makes no sense. Doing nothing." % option)
	
	if src == 'view':
		return HttpResponseRedirect(course_reverse('forum_view_entries',TheCourse,thread_id=TheThread.id))

	return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
Management.register_interface('Forum','ASSISTANT;INSTRUCTOR','alter_thread',alter_thread)

def ban_user(request, TheCourseParticipant, TheCourse, course_participant_id):
	logger.fxn_entry('Altering ban of participant %s of course %s',course_participant_id, TheCourse)
	BanningCourseParticipant = CourseParticipant.find(id=course_participant_id)
	
	if not BanningCourseParticipant:
		logger.forced_redirect("CourseParticipant %s does not exist, returning to forum management",course_participant_id)
		messages.info(request,"User not found for this course")
		return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
	
	BanInfo = ForumBan.objects.filter(course_participant=BanningCourseParticipant) or None
	if BanInfo: BanInfo = BanInfo[0]
	
	if request.method == "POST":
		Error = False
		BanForm = ForumBanForm(request.POST,instance=BanInfo)
		if BanForm.is_valid():
			if BanForm.has_changed():
				BanForm.instance.course_participant = BanningCourseParticipant
				BanForm.instance.forum = TheCourse.forum
				Ban = BanForm.save()
				if Ban.forum_ban == 0 and Ban.message_ban == 0:
					Ban.delete()
					logger.info("Ban restrictions lifted for %s. Ban deleted" % BanningCourseParticipant)
			else: logger.form_unchanged("ForumBanForm unchanged")
		else: Error = True; logger.error("ForumBanForm invalid - %s" % BanForm)
		if not Error:
			return HttpResponseRedirect(course_reverse('management',TheCourse,app='forum',command='manage'))
	else:
		BanForm = ForumBanForm(instance=BanInfo)
	return render_to_response('forum/management/ban.html',{'TheForum':TheCourse.forum,'TheCourse':TheCourse,'BanForm':BanForm,'BanningCourseParticipant':BanningCourseParticipant},context_instance=RequestContext(request))
Management.register_interface('Forum','ASSISTANT;INSTRUCTOR','ban',ban_user)

def view_messages(request, TheCourseParticipant, TheCourse, username, page=1):
	logger.fxn_entry("Showing admin %s all of user %s's message",TheCourseParticipant.user,username)

	TargetUser = User.find_or_404(username)
	
	message_list = ForumPrivateMessage.objects.filter(sender=TargetUser,send_date__isnull=False).order_by('-send_date')
	paginator = EmptyPaginator(message_list, 20) #Show 20 entries per page
	try:
		message_list = paginator.page(page)
	except PageNotAnInteger:
		# If page is not an integer, deliver first page.
		message_list = paginator.page(1)
	except EmptyPage:
		# If page is out of range (e.g. 9999), deliver last page of results.
		message_list = paginator.page(paginator.num_pages)
	
	message_list.pages_left = paginator.num_pages - message_list.number
	logger.fxn_exit("Returning message list")
	return render_to_response('forum/management/list_messages.html',{'TheForum':TheCourse.forum,'TheCourse':TheCourse,'TargetUser':TargetUser,'page':message_list},context_instance=RequestContext(request))
Management.register_interface('Forum','ASSISTANT;INSTRUCTOR','view_messages',view_messages)


